package com.nidu.demo.dept.gatewayimpl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.cola.dto.PageResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nidu.demo.common.constants.Constants;
import com.nidu.demo.dept.dto.DepartmentListQry;
import com.nidu.demo.dept.dto.DepartmentPageQry;
import com.nidu.demo.dept.dto.DepartmentTreeQry;
import com.nidu.demo.dept.convertor.DepartmentConvertor;
import com.nidu.demo.dept.gateway.DepartmentGateway;
import com.nidu.demo.dept.mapper.DepartmentMapper;
import com.nidu.demo.dept.mapper.dataobject.DepartmentDO;
import com.nidu.demo.dept.model.Department;
import com.nidu.demo.dept.model.DepartmentCriteria;
import com.nidu.demo.dept.util.DepartmentUtil;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Set;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 部门网关实现
 *
 * @author auto
 */
@Component
@RequiredArgsConstructor
public class DepartmentGatewayImpl implements DepartmentGateway {

    private final DepartmentMapper mapper;
    private final DepartmentConvertor convertor;

    @Override
    public Department create(Department dept) {
        DepartmentDO deptDO = convertor.toDataObject(dept);
        mapper.insert(deptDO);
        return convertor.toDomainObject(deptDO);
    }

    @Override
    public Department update(Department dept) {
        DepartmentDO deptDO = convertor.toDataObject(dept);
        mapper.updateById(deptDO);
        return convertor.toDomainObject(deptDO);
    }

    @Override
    public void deleteById(Long id) {
        mapper.deleteById(id);
    }

    @Override
    public void deleteByIds(Set<Long> ids) {
        mapper.deleteByIds(ids);
    }

    @Override
    public Department getById(Long id) {
        DepartmentDO deptDO = mapper.selectById(id);
        if(deptDO == null){
            return null;
        }
        return convertor.toDomainObject(deptDO);
    }

    @Override
    public List<Department> getByIds(Set<Long> ids) {
        LambdaQueryWrapper<DepartmentDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(DepartmentDO::getId, ids);
        List<DepartmentDO> deptDOS = mapper.selectList(wrapper);
        if(CollUtil.isEmpty(deptDOS)){
            return new ArrayList<>();
        }
        return convertor.toDomainObjects(deptDOS);
    }

    @Override
    public Department getByCodeAndCompanyId(String code, Long companyId) {
        DepartmentDO deptDO = mapper.selectByCodeAndCompanyId(code, companyId);
        if(deptDO == null){
            return null;
        }
        return convertor.toDomainObject(deptDO);
    }

    @Override
    public List<Department> getByParentId(Long parentId) {
        LambdaQueryWrapper<DepartmentDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DepartmentDO::getParentId, parentId);
        List<DepartmentDO> deptDOS = mapper.selectList(wrapper);
        return convertor.toDomainObjects(deptDOS);
    }

    @Override
    public List<Department> listByCondition(DepartmentCriteria criteria) {
        LambdaQueryWrapper<DepartmentDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(criteria.getStatus() != null, DepartmentDO::getStatus, criteria.getStatus());
        wrapper.in(!CollUtil.isEmpty(criteria.getDeptIds()), DepartmentDO::getId, criteria.getDeptIds());

        wrapper.like(!StrUtil.isEmpty(criteria.getDeptName()), DepartmentDO::getName, criteria.getDeptName());
        wrapper.eq(!StrUtil.isEmpty(criteria.getDeptCode()), DepartmentDO::getCode, criteria.getDeptCode());
        wrapper.eq(criteria.getParentId() != null, DepartmentDO::getParentId, criteria.getParentId());
        wrapper.eq(criteria.getCompanyId() != null, DepartmentDO::getCompanyId, criteria.getCompanyId());

        List<DepartmentDO> deptDOS = mapper.selectList(wrapper);
        if(CollUtil.isEmpty(deptDOS)){
            return new ArrayList<>();
        }
        return convertor.toDomainObjects(deptDOS);
    }

    @Override
    public List<Department> treeByCondition(DepartmentCriteria criteria) {
        LambdaQueryWrapper<DepartmentDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(criteria.getStatus() != null, DepartmentDO::getStatus, criteria.getStatus());

        LocalDateTime[] createTime = criteria.getCreateTime();
        if (createTime != null) {
            if (createTime.length == 1 && createTime[0] != null) {
                wrapper.ge(DepartmentDO::getCreateTime, createTime[0]);
            } else if (createTime.length > 1 && createTime[0] != null && createTime[1] != null) {
                wrapper.between(DepartmentDO::getCreateTime, createTime[0], createTime[1]);
            }
        }

        wrapper.like(!StrUtil.isEmpty(criteria.getDeptName()), DepartmentDO::getName, criteria.getDeptName());
        wrapper.eq(!StrUtil.isEmpty(criteria.getDeptCode()), DepartmentDO::getCode, criteria.getDeptCode());
        wrapper.eq(criteria.getCompanyId() != null, DepartmentDO::getCompanyId, criteria.getCompanyId());
        List<DepartmentDO> deptDOS = mapper.selectList(wrapper);
        if(CollUtil.isEmpty(deptDOS)){
            return new ArrayList<>();
        }
        return convertor.toDomainObjects(deptDOS);
    }

    @Override
    public PageResponse<Department> pageByCondition(DepartmentCriteria criteria) {
        // 1. 查询所有部门
        LambdaQueryWrapper<DepartmentDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(criteria.getStatus() != null, DepartmentDO::getStatus, criteria.getStatus());

        LocalDateTime[] createTime = criteria.getCreateTime();
        if (createTime != null) {
            if (createTime.length == 1 && createTime[0] != null) {
                wrapper.ge(DepartmentDO::getCreateTime, createTime[0]);
            } else if (createTime.length > 1 && createTime[0] != null && createTime[1] != null) {
                wrapper.between(DepartmentDO::getCreateTime, createTime[0], createTime[1]);
            }
        }

        List<DepartmentDO> deptDOS = mapper.selectList(wrapper);
        if(CollUtil.isEmpty(deptDOS)){
            return PageResponse.of(criteria.getPageSize(), criteria.getPageIndex());
        }
        List<Department> deptList = convertor.toDomainObjects(deptDOS);

        // 2. 找出所有根节点（parentId = 0）
        List<Department> rootDepts = deptList.stream()
                .filter(dept -> Constants.ROOT_DEPT_ID.equals(dept.getParentId()))
                .sorted(Comparator.comparing(Department::getSortOrder))
                .collect(Collectors.toList());

        int total = rootDepts.size();
        int fromIndex = Math.min((criteria.getPageIndex() - 1) * criteria.getPageSize(), total);
        int toIndex = Math.min(fromIndex + criteria.getPageSize(), total);
        if (fromIndex >= toIndex) {
            return PageResponse.of(criteria.getPageSize(), criteria.getPageIndex());
        }

        // 3. 获取分页根节点
        List<Department> pagedRoots = rootDepts.subList(fromIndex, toIndex);

        // 4. 查找所有子孙节点
        Set<Long> rootIds = pagedRoots.stream().map(Department::getId).collect(Collectors.toSet());
        List<Department> descendants = DepartmentUtil.findDescendants(deptList, rootIds);

        // 5. 合并成最终返回数据
        List<Department> pageData = new ArrayList<>();
        pageData.addAll(pagedRoots);
        pageData.addAll(descendants);

        return PageResponse.of(pageData, rootDepts.size(), criteria.getPageSize(), criteria.getPageIndex());
    }

    @Override
    public void updateStatus(Long id, Integer status) {
        DepartmentDO deptDO = new DepartmentDO();
        deptDO.setId(id);
        deptDO.setStatus(status);
        mapper.updateById(deptDO);
    }

    @Override
    public Set<Long> getAllChildrenIds(Long deptId) {
        // 2. 构建查询条件：ancestors包含当前部门ID的所有部门
        LambdaQueryWrapper<DepartmentDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(DepartmentDO::getId)
                .and(w -> w.like(DepartmentDO::getAncestors, "," + deptId + ",")
                          .or()
                          .likeRight(DepartmentDO::getAncestors, deptId + ",")
                          .or()
                          .likeLeft(DepartmentDO::getAncestors, "," + deptId));

        // 3. 查询所有子部门ID
        List<DepartmentDO> childrenDepts = mapper.selectList(wrapper);
        Set<Long> childrenIds = childrenDepts.stream()
                .map(DepartmentDO::getId)
                .collect(Collectors.toSet());

        // 4. 添加当前部门ID
        childrenIds.add(deptId);

        return childrenIds;
    }
} 